﻿using Coldairarrow.Business.AOP;
using Coldairarrow.Business.IT;
using Coldairarrow.Business.PB;
using Coldairarrow.Entity.Base_Manage;
using Coldairarrow.Entity.DTO;
using Coldairarrow.Entity.IT;
using Coldairarrow.Entity.PB;
using Coldairarrow.Entity.TD;
using Coldairarrow.IBusiness;
using Coldairarrow.IBusiness.DTO;
using Coldairarrow.Util;
using EFCore.Sharding;
using LinqKit;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using NPOI.SS.Formula.Functions;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Dynamic.Core;
using System.Linq.Expressions;
using System.Threading.Tasks;

namespace Coldairarrow.Business.TD
{
    public partial class TD_OutStorageBusiness : BaseBusiness<TD_OutStorage>, ITD_OutStorageBusiness, ITransientDependency
    {
        public async Task<PageResult<TD_OutStorageDTO>> GetDataListAsync(TD_OutStoragePageInput input)
        {
            Expression<Func<TD_OutStorage, Base_User, Base_User, PB_Project,TD_OutStorageDTO>> selectskss = (a, b, c,d) => new TD_OutStorageDTO
            {
                ShnheName = b.RealName,
                CaozuoName = c.RealName,
                ProjectName=d.Name,
            };
            selectskss = selectskss.BuildExtendSelectExpre();
            var q = from a in Db.GetIQueryable<TD_OutStorage>().AsExpandable()
                    join b in Db.GetIQueryable<Base_User>() on a.AuditUserId equals b.Id into ab
                    from b in ab.DefaultIfEmpty()
                    join c in Db.GetIQueryable<Base_User>() on a.CreatorId equals c.Id into ac
                    from c in ac.DefaultIfEmpty()
                    join d in Db.GetIQueryable<PB_Project>() on a.ProjectId equals d.Id into ad
                    from d in ad.DefaultIfEmpty()
                    select selectskss.Invoke(a, b, c,d);
            var where = LinqHelper.True<TD_OutStorageDTO>();
            var search = input.Search;
            //如果物料不为空 和 货位 
            if (!search.MaterialName.IsNullOrEmpty() || !search.LocalName.IsNullOrEmpty() || !search.ConfirmUserIdName.IsNullOrEmpty())
            {
                //TD_OutStorDetail  子表
                Expression<Func<TD_OutStorDetail, PB_Material, PB_Location, Base_User, TD_OutStorDetailDTO>> selectsk = (a, b, c, d) => new TD_OutStorDetailDTO
                {
                    MaterialIdName = b.Name,
                    LocalIdName = c.Name,
                    ConfirmUserIdName = d.RealName,
                };
                selectsk = selectsk.BuildExtendSelectExpre();
                var k = from a in Db.GetIQueryable<TD_OutStorDetail>().AsExpandable()
                        join b in Db.GetIQueryable<PB_Material>() on a.MaterialId equals b.Id into ab
                        from b in ab.DefaultIfEmpty()
                        join c in Db.GetIQueryable<PB_Location>() on a.LocalId equals c.Id into ac
                        from c in ac.DefaultIfEmpty()
                        join d in Db.GetIQueryable<Base_User>() on a.CreatorId equals d.Id into ad
                        from d in ad.DefaultIfEmpty()

                        select @selectsk.Invoke(a, b, c, d);
                if (!search.MaterialName.IsNullOrEmpty())
                    k = k.Where(x => x.MaterialIdName.Contains(search.MaterialName));
                if (!search.LocalName.IsNullOrEmpty())
                    k = k.Where(x => x.LocalIdName.Contains(search.LocalName));
                if (!search.ConfirmUserIdName.IsNullOrEmpty())
                    k = k.Where(x => x.ConfirmUserIdName.Contains(search.ConfirmUserIdName));


          
                var res = await k.ToListAsync();
                var list = res.GroupBy(x => new { x.OutStorId }).Select(x => new { OutStorId = x.Key.OutStorId });
                List<String> names = new List<string>();
                foreach (var item in list)
                {
                    names.Add(item.OutStorId);
                }
                q = q.Where(x => names.Contains(x.Id));
            }

            if (!search.Status.ToString().IsNullOrEmpty())
            {
                where = where.And(w => w.Status == search.Status);
            }
            if (!search.Code.IsNullOrEmpty())
                where = where.And(w => w.Id.Contains(search.Code) || w.RefCode.Contains(search.Code));
            if (!search.OutType.IsNullOrEmpty())
                where = where.And(w => w.OutType == search.OutType);
            if (search.OutStorTimeStart.HasValue)
                where = where.And(w => w.OutTime >= search.OutStorTimeStart.Value);
            if (search.OutStorTimeEnd.HasValue)
                where = where.And(w => w.OutTime <= search.OutStorTimeEnd.Value);
            where = where.And(m=>_operator.Property.DeptIds.Contains(m.DepId));
            return await q.Where(where).GetPageResultAsync(input);
        }

        public async Task<TD_OutStorage> GetTheDataAsync(string id)
        {
            return await this.GetIQueryable()
                .Include(i => i.OutStorDetails)
                    .ThenInclude(t => t.Location)
                .Include(i => i.OutStorDetails)
                    .ThenInclude(t => t.Material)
                .Include(i => i.OutStorDetails)
                    .ThenInclude(t => t.StorArea)
                .Include(i => i.OutStorDetails)
                    .ThenInclude(t => t.Store)
                .Include(i => i.OutStorDetails)
                    .ThenInclude(t => t.Rack)
                .Include(i=>i.OutStorRecords)
                    .ThenInclude(t => t.Material)
                .SingleOrDefaultAsync(w => w.Id == id);
        }

        public async Task<TD_OutStorageViewDTO> GetTheDataAsyncs(string id)
        {
            TD_OutStorageViewDTO pblist = new TD_OutStorageViewDTO();
            TD_OutStorage Datalist = await Db.GetIQueryable<TD_OutStorage>().Where(x => x.Id == id).FirstOrDefaultAsync();
            //将父类对象赋值转换成子类对象
            pblist = AutoAdaptation.AutoCopy<TD_OutStorage, TD_OutStorageViewDTO>(Datalist);

            Expression<Func<TD_OutStorDetail, PB_Material, PB_Location, PB_Rack, PB_StorArea, Base_Department, TD_OutStorDetailViewDTO>> select = (a, b, c, d, e,f) => new TD_OutStorDetailViewDTO
            {
                MaterialName = b.Name,//物料名称
                MaterialCode = b.Code, //物料编码
                MaterialSpec = b.Spec, //物料规格 
                AreaName = e.Name, //货区名称
                RackName = d.Name,//货架名称
                LocationName =c.Name, //货位名称
                StoreName =f.Name, //仓库名称
            };
            select = select.BuildExtendSelectExpre();
            var q = from a in Db.GetIQueryable<TD_OutStorDetail>().AsExpandable().Where(x => x.OutStorId == id)
                    join b in Db.GetIQueryable<PB_Material>() on a.MaterialId equals b.Id into ab
                    from b in ab.DefaultIfEmpty()
                    join c in Db.GetIQueryable<PB_Location>() on a.LocalId equals c.Id into ac
                    from c in ac.DefaultIfEmpty()
                    join d in Db.GetIQueryable<PB_Rack>() on c.RackId equals d.Id into cd
                    from d in cd.DefaultIfEmpty()
                    join e in Db.GetIQueryable<PB_StorArea>() on c.AreaId equals e.Id into ce
                    from e in ce.DefaultIfEmpty()
                    join f in Db.GetIQueryable<Base_Department>() on a.StorId equals f.Id into af
                    from f in af.DefaultIfEmpty()
                    select @select.Invoke(a, b, c, d, e,f);

            Expression<Func<TD_OutStorRecord, PB_Material, TD_OutStorRecordViewDTO>> selects = (a, b) => new TD_OutStorRecordViewDTO
            {
                MaterialName = b.Name,//物料名称
                MaterialCode = b.Code, //物料编码
                MaterialSpec = b.Spec, //物料规格 
            };

            selects = selects.BuildExtendSelectExpre();
            var w = from a in Db.GetIQueryable<TD_OutStorRecord>().AsExpandable().Where(x => x.OutStorId == id)
                    join b in Db.GetIQueryable<PB_Material>() on a.MaterialId equals b.Id into ab
                    from b in ab.DefaultIfEmpty()
                    select @selects.Invoke(a, b);

            pblist.OutStorDetails = await q.ToListAsync();
            pblist.OutStorRecords = await w.ToListAsync();

            return pblist;

        }




        //[LockOutStor]
        [DataAddLog(UserLogType.出库管理, "Code", "出库单")]
        [Transactional]
        public async Task AddDataAsync(TD_OutStorage data)
        {
            if (data.Code.IsNullOrEmpty())
            {
                data.Code = DateTime.Now.ToString("yyyyMMddHHmmss");
            }
            var detpdata = await _opdept.GetOperatorDept();
            TD_OutStorage tD_OutStorage = new TD_OutStorage();
            tD_OutStorage.Id = data.Id;
            tD_OutStorage.Code = data.Code;
            tD_OutStorage.StorageId = data.StorageId;
            tD_OutStorage.OutTime = data.OutTime;
            tD_OutStorage.OutType = data.OutType;
            tD_OutStorage.RefCode = data.RefCode;
            tD_OutStorage.OutNum = data.OutStorDetails.Sum(s => s.OutNum);
            tD_OutStorage.TotalAmt = data.OutStorDetails.Sum(s => s.TotalAmt);
            tD_OutStorage.Status = 0;
            tD_OutStorage.CusId = data.CusId;
            tD_OutStorage.Address = data.Address;
            tD_OutStorage.Remarks = data.Remarks;
            tD_OutStorage.CreatorId = _operator.UserId;
            tD_OutStorage.CreateTime = DateTime.Now;
            tD_OutStorage.Deleted = false;
            tD_OutStorage.DepId = detpdata.DetpId;
            await Db.InsertAsync<TD_OutStorage>(tD_OutStorage);
            List<TD_OutStorDetail> tD_OutStorDetaillist = new List<TD_OutStorDetail>();
            foreach (var item in data.OutStorDetails)
            {
                TD_OutStorDetail tD_OutStorDetail = new TD_OutStorDetail();
                tD_OutStorDetail.Id = item.Id;
                tD_OutStorDetail.StorId = item.StorId;
                tD_OutStorDetail.OutStorId = item.OutStorId;
                tD_OutStorDetail.LocalId = item.LocalId;
                tD_OutStorDetail.AreaId = item.AreaId;
                tD_OutStorDetail.RackId = item.RackId;
                tD_OutStorDetail.BarCode = item.BarCode;
                tD_OutStorDetail.MaterialId = item.MaterialId;
                //tD_OutStorDetail.BatchNo = item.BatchNo;
                tD_OutStorDetail.Price = item.Price;
                tD_OutStorDetail.TotalAmt = item.TotalAmt;
                tD_OutStorDetail.LocalNum = item.LocalNum;
                tD_OutStorDetail.OutNum = item.OutNum;
                tD_OutStorDetail.CreateTime = DateTime.Now;
                tD_OutStorDetail.CreatorId = _operator.UserId;
                tD_OutStorDetail.Deleted = false;
                tD_OutStorDetaillist.Add(tD_OutStorDetail);
            }
            await Db.InsertAsync<TD_OutStorDetail>(tD_OutStorDetaillist);
            List<TD_OutStorRecord> tD_OutStorRecordlist = new List<TD_OutStorRecord>();
            var list = data.OutStorDetails.GroupBy(s => new { s.MaterialId, s.Price, s.StorId }).Select(x => new { MaterialId = x.Key.MaterialId, Price = x.Key.Price, StorId=x.Key.StorId, Num = x.Sum(i => i.OutNum), TotalAmt = x.Sum(i => i.TotalAmt) });
            foreach (var item in list)
            {
                TD_OutStorRecord tD_OutStorRecord = new TD_OutStorRecord();
                tD_OutStorRecord.Id = IdHelper.GetId();
                tD_OutStorRecord.StorId = item.StorId;
                tD_OutStorRecord.OutStorId = data.Id;
                tD_OutStorRecord.MaterialId = item.MaterialId;
                tD_OutStorRecord.Price = item.Price;
                tD_OutStorRecord.TotalAmt = item.TotalAmt;
                tD_OutStorRecord.OutNum = item.Num;
                tD_OutStorRecord.CreateTime = DateTime.Now;
                tD_OutStorRecord.CreatorId = _operator.UserId;
                tD_OutStorRecord.Deleted = false;
                tD_OutStorRecordlist.Add(tD_OutStorRecord);
            }
            await Db.InsertAsync<TD_OutStorRecord>(tD_OutStorRecordlist);

            //增加台账记录。牟俊明。2022.7.8
            //var bookSvc = _ServiceProvider.GetRequiredService<IIT_RecordBookBusiness>();
            //await bookSvc.AddByTypeAsync(data.Id, "Out");

        }

        //[LockOutStor]
        [Transactional]
        public async Task UpdateDetailAsync(TD_OutStorage data)
        {
            List<TD_OutStorDetail> tD_OutStorDetaillist = new List<TD_OutStorDetail>();
            foreach (var item in data.OutStorDetails)
            {
                TD_OutStorDetail tD_OutStorDetail = new TD_OutStorDetail();
                tD_OutStorDetail.Id = item.Id;
                tD_OutStorDetail.StorId = item.StorId;
                tD_OutStorDetail.OutStorId = item.OutStorId;
                tD_OutStorDetail.LocalId = item.LocalId;
                tD_OutStorDetail.AreaId = item.AreaId;
                tD_OutStorDetail.RackId = item.RackId;
                tD_OutStorDetail.BarCode = item.BarCode;
                tD_OutStorDetail.MaterialId = item.MaterialId;
                //tD_OutStorDetail.BatchNo = item.BatchNo;
                tD_OutStorDetail.Price = item.Price;
                tD_OutStorDetail.TotalAmt = item.TotalAmt;
                tD_OutStorDetail.LocalNum = item.LocalNum;
                tD_OutStorDetail.OutNum = item.OutNum;
                tD_OutStorDetail.CreateTime = DateTime.Now;
                tD_OutStorDetail.CreatorId = _operator.UserId;
                tD_OutStorDetail.Deleted = false;
                tD_OutStorDetaillist.Add(tD_OutStorDetail);
            }
            await Db.InsertAsync<TD_OutStorDetail>(tD_OutStorDetaillist);
            List<TD_OutStorRecord> tD_OutStorRecordlist = new List<TD_OutStorRecord>();
            var list = data.OutStorDetails.GroupBy(s => new { s.MaterialId, s.Price, s.StorId }).Select(x => new { MaterialId = x.Key.MaterialId, Price = x.Key.Price, StorId = x.Key.StorId, Num = x.Sum(i => i.OutNum), TotalAmt = x.Sum(i => i.TotalAmt) });
            foreach (var item in list)
            {
                TD_OutStorRecord tD_OutStorRecord = new TD_OutStorRecord();
                tD_OutStorRecord.Id = IdHelper.GetId();
                tD_OutStorRecord.StorId = item.StorId;
                tD_OutStorRecord.OutStorId = data.Id;
                tD_OutStorRecord.MaterialId = item.MaterialId;
                tD_OutStorRecord.Price = item.Price;
                tD_OutStorRecord.TotalAmt = item.TotalAmt;
                tD_OutStorRecord.OutNum = item.Num;
                tD_OutStorRecord.CreateTime = DateTime.Now;
                tD_OutStorRecord.CreatorId = _operator.UserId;
                tD_OutStorRecord.Deleted = false;
                tD_OutStorRecordlist.Add(tD_OutStorRecord);
            }
            await Db.InsertAsync<TD_OutStorRecord>(tD_OutStorRecordlist);

            TD_OutStorage tD_OutStorage = await Db.GetIQueryable<TD_OutStorage>().Where(s => s.Id == data.Id).FirstOrDefaultAsync();
            tD_OutStorage.Code = data.Code;
            tD_OutStorage.StorageId = data.StorageId;
            tD_OutStorage.OutTime = data.OutTime;
            tD_OutStorage.OutType = data.OutType;
            tD_OutStorage.RefCode = data.RefCode;
            tD_OutStorage.OutNum = data.OutStorDetails.Sum(s => s.OutNum);
            tD_OutStorage.TotalAmt = data.OutStorDetails.Sum(s => s.TotalAmt);
            tD_OutStorage.Status = 0;
            tD_OutStorage.CusId = data.CusId;
            tD_OutStorage.Address = data.Address;
            tD_OutStorage.Remarks = data.Remarks;
            List<string> props = GetFieldList(tD_OutStorage);
            if (props.IsNullOrEmpty())
            {
                await UpdateAsync(tD_OutStorage);
            }
            else
            {
                await UpdateAsync(tD_OutStorage, props);
            }
        }
        [DataEditLog(UserLogType.出库管理, "Code", "出库单")]
        public async Task UpdateDataAsync(TD_OutStorage data)
        {
            var curDetail = data.OutStorDetails;
            var listDetail = await Db.GetIQueryable<TD_OutStorDetail>().Where(w => w.OutStorId == data.Id).ToListAsync();

            var curIds = curDetail.Select(s => s.Id).ToList();
            var dbIds = listDetail.Select(s => s.Id).ToList();
            var deleteIds = dbIds.Except(curIds).ToList();
            var detailSvc = _ServiceProvider.GetRequiredService<ITD_OutStorDetailBusiness>();
            if (deleteIds.Count > 0)
                await detailSvc.DeleteDataAsync(deleteIds);

            var addIds = curIds.Except(dbIds).ToList();
            if (addIds.Count > 0)
            {
                var listAdds = curDetail.Where(w => addIds.Contains(w.Id)).ToList();
                await detailSvc.AddDataAsync(listAdds);
            }

            var updateIds = curIds.Except(addIds).ToList();
            if (updateIds.Count > 0)
            {
                var listUpdates = curDetail.Where(w => updateIds.Contains(w.Id)).ToList();
                await detailSvc.UpdateDataAsync(listUpdates);
            }

            data.OutNum = data.OutStorDetails.Sum(s => s.OutNum);
            data.TotalAmt = data.OutStorDetails.Sum(s => s.TotalAmt);
          
            await UpdateAsync(data);
        }

        [DataEditLog(UserLogType.出库管理, "Id", "出库单审批")]
        [Transactional]
        public async Task Approve(AuditDTO audit)
        {
            var now = DateTime.Now;
            var data = await this.GetTheDataAsync(audit.Id);
            var detail = data.OutStorDetails;
            var dicMUnit = detail.Select(s => new { s.MaterialId, s.Material.UnitGroupId }).GroupBy(g => new { g.MaterialId, g.UnitGroupId }).ToDictionary(k => k.Key.MaterialId, v => v.Key.UnitGroupId);

            var lmSvc = _ServiceProvider.GetRequiredService<IIT_LocalMaterialBusiness>();
            var ldSvc = _ServiceProvider.GetRequiredService<IIT_LocalDetailBusiness>();

            // 减库存明细
            {
                //await UpdateAsync(data);
                var ldGrout = detail
                    .GroupBy(g => new { g.StorId, g.LocalId,  g.MaterialId, g.BatchNo, g.BarCode, g.Price })
                    .Select(s => new { s.Key.StorId, s.Key.LocalId,  s.Key.MaterialId, s.Key.BatchNo, s.Key.BarCode, s.Key.Price, TotalAmt = s.Sum(o => o.TotalAmt), Num = s.Sum(o => o.OutNum) })
                    .ToList();
                //查询当前库存明细记录
                var localIds = ldGrout.Select(s => s.LocalId).ToList();
                var materIds = ldGrout.Select(s => s.MaterialId).ToList();
                var batchNos = ldGrout.Select(s => s.BatchNo).ToList();
                var barCodes = ldGrout.Select(s => s.BarCode).ToList();

                var listLd = Db.GetIQueryable<IT_LocalDetail>();
                listLd = listLd.Where(w => w.StorId == audit.StorId);
                if (localIds.Count > 0)
                    listLd = listLd.Where(w => localIds.Contains(w.LocalId));
                if (materIds.Count > 0)
                    listLd = listLd.Where(w => materIds.Contains(w.MaterialId));
                if (batchNos.Count > 0)
                    listLd = listLd.Where(w => batchNos.Contains(w.BatchNo));
                if (barCodes.Count > 0)
                    listLd = listLd.Where(w => barCodes.Contains(w.BarCode));
                var lmDbData = await listLd.ToListAsync();

                //处理库存明细
                var localMaterialSvc = _ServiceProvider.GetRequiredService<IIT_LocalDetailBusiness>();
                var listLmUpdate = new List<IT_LocalDetail>();
                var listDel = new List<IT_LocalDetail>();
                foreach (var lm in ldGrout)
                {
                    var lmNum = lm.Num;
                    var lds = lmDbData.Where(w => w.StorId == audit.StorId && w.LocalId == lm.LocalId && w.MaterialId == lm.MaterialId && w.BatchNo == lm.BatchNo && w.BarCode == lm.BarCode).OrderBy(o => o.InTime).ToList();
                    if (lds.Sum(s => s.Num) < lmNum) throw new Exception($"库存(明细)数量不够({lm.Num})");
                    foreach (var item in lds)
                    {
                        if (item.Num <= lmNum)
                        {
                            listDel.Add(item);
                            lmNum -= item.Num.GetValueOrDefault(0);
                        }
                        else
                        {
                            item.Num -= lmNum;
                            listLmUpdate.Add(item);
                            lmNum = 0;
                        }
                        if (lmNum == 0) break;
                    }
                }
                if (listDel.Count > 0) await ldSvc.DeleteDataAsync(listDel);
                if (listLmUpdate.Count > 0) await ldSvc.UpdateDataAsync(listLmUpdate);

            }

            // 减除库存
            {
                var lmGrout = detail
                    .GroupBy(g => new { g.StorId, g.LocalId, g.MaterialId, g.BatchNo, g.BarCode })
                    .Select(s => new { s.Key.StorId, s.Key.LocalId,  s.Key.MaterialId, s.Key.BatchNo, s.Key.BarCode, Num = s.Sum(o => o.OutNum) })
                    .ToList();
                //查询当前库存记录
                var localIds = lmGrout.Select(s => s.LocalId).ToList();
                var materIds = lmGrout.Select(s => s.MaterialId).ToList();
                var batchNos = lmGrout.Select(s => s.BatchNo).ToList();
                var barCodes = lmGrout.Select(s => s.BarCode).ToList();

                var lmQuery = Db.GetIQueryable<IT_LocalMaterial>();
                lmQuery = lmQuery.Where(w => w.StorId == audit.StorId);
                if (localIds.Count > 0)
                    lmQuery = lmQuery.Where(w => localIds.Contains(w.LocalId));
                if (materIds.Count > 0)
                    lmQuery = lmQuery.Where(w => materIds.Contains(w.MaterialId));
                var lmDbData = await lmQuery.ToListAsync();

                //处理库存
                var listLmUpdate = new List<IT_LocalMaterial>();
                var listDel = new List<IT_LocalMaterial>();
                foreach (var lm in lmGrout)
                {
                    var lds = lmDbData.Where(w => w.StorId == audit.StorId && w.LocalId == lm.LocalId  && w.MaterialId == lm.MaterialId ).SingleOrDefault();
                    if (lds == null || lds.Nums_N < lm.Num) throw new Exception($"没有找到对应物料的库存数据/库存数量不够({lm.Num})");
                    if (lds.Nums_N == lm.Num) listDel.Add(lds);
                    else if (lds.Nums_N > lm.Num)
                    {
                        lds.Nums_N -= lm.Num;
                        listLmUpdate.Add(lds);
                    }
                }
                if (listDel.Count > 0) await lmSvc.DeleteDataAsync(listDel);
                if (listLmUpdate.Count > 0) await lmSvc.UpdateDataAsync(listLmUpdate);
            }

            // 添加台帐
            {
                var lmGrout = detail
                    .GroupBy(g => new { g.StorId, g.LocalId, g.MaterialId, g.BatchNo, g.BarCode })
                    .Select(s => new { s.Key.StorId, s.Key.LocalId, s.Key.MaterialId, s.Key.BatchNo, s.Key.BarCode, Num = s.Sum(o => o.OutNum) })
                    .ToList();

                var listRB = new List<IT_RecordBook>();
                foreach (var item in lmGrout)
                {
                    var rb = new IT_RecordBook();
                    rb.Id = IdHelper.GetId();
                    rb.RefCode = data.Code;
                    rb.Type = "Out";
                    rb.ToStorId = item.StorId;
                    rb.ToLocalId = item.LocalId;
                    rb.MaterialId = item.MaterialId;
                    rb.MeasureId = dicMUnit[item.MaterialId];
                    rb.BatchNo = item.BatchNo;
                    rb.BarCode = item.BarCode;
                    rb.Num = item.Num;
                    rb.CreateTime = now;
                    rb.CreatorId = audit.AuditUserId;
                    rb.Deleted = false;
                    listRB.Add(rb);
                }
                if (listRB.Count > 0)
                {
                    var bookSvc = _ServiceProvider.GetRequiredService<IIT_RecordBookBusiness>();
                    await bookSvc.AddDataAsync(listRB);
                }
            }

            // 处理托盘位置数据
            //{
            //    var dicTray = new Dictionary<string, string>();
            //    foreach (var item in detail)
            //    {
            //        if (item.TrayId != null && !dicTray.ContainsKey(item.TrayId))
            //            dicTray.Add(item.TrayId, item.LocalId);
            //    }
            //    var trayIds = dicTray.Keys.ToList();
            //    if (trayIds.Count > 0)
            //    {
            //        var listTray = await Service.GetIQueryable<PB_Tray>().Where(w => trayIds.Contains(w.Id)).ToListAsync();
            //        foreach (var tray in listTray)
            //        {
            //            tray.LocalId = dicTray[tray.Id];
            //        }
            //        var traySvc = _ServiceProvider.GetRequiredService<IPB_TrayBusiness>();
            //        await traySvc.UpdateDataAsync(listTray);
            //    }
            //}

            // 解锁货位 在自动出库的时候，货位可能被出库锁锁定了
            {
                var localIds = data.OutStorDetails.Select(s => s.LocalId).ToList();
                var listLocal = await Db.GetIQueryable<PB_Location>().Where(w => localIds.Contains(w.Id) && w.LockType == 2).ToListAsync();
                foreach (var item in listLocal)
                {
                    item.LockType = 0;
                }
                var localSvc = _ServiceProvider.GetRequiredService<IPB_LocationBusiness>();
                await localSvc.UpdateDataAsync(listLocal);
            }

            // 修改出库状态 
            {
                data.Status = 1;
                data.AuditeTime = audit.AuditTime;
                data.AuditUserId = audit.AuditUserId;
                await UpdateAsync(data);
            }
        }

        [DataEditLog(UserLogType.出库管理, "Id", "出库单驳回")]
        public async Task Reject(AuditDTO audit)
        {
            var data = await this.GetTheDataAsync(audit.Id);
            // 修改出库状态
            {
                data.Status = 2;
                data.AuditeTime = audit.AuditTime;
                data.AuditUserId = audit.AuditUserId;
                await UpdateAsync(data);
            }

            // 解锁货位 在自动出库的时候，货位可能被出库锁锁定了
            {
                var localIds = data.OutStorDetails.Select(s => s.LocalId).ToList();
                var listLocal = await Db.GetIQueryable<PB_Location>().Where(w => localIds.Contains(w.Id) && w.LockType == 2).ToListAsync();
                foreach (var item in listLocal)
                {
                    item.LockType = 0;
                }
                var localSvc = _ServiceProvider.GetRequiredService<IPB_LocationBusiness>();
                await localSvc.UpdateDataAsync(listLocal);
            }
        }
        [DataEditLog(UserLogType.出库管理, "Id", "出库单审批")]
        [Transactional]
        public async Task OutApprove(AuditDTO audit)
        {
            var data = await this.GetTheDataAsync(audit.Id);
            // 修改主数据状态
            {
                data.Status = 1;
                data.AuditeTime = audit.AuditTime;
                data.AuditUserId = audit.AuditUserId;
                await UpdateAsync(data);
            }
            //只有无码出库更改库存，其他出库不更新库存  朱柏清2022-02-25
            if (data.OutType == "WithoutQRCode")
            {
                Base_User bdata = await Db.GetIQueryable<Base_User>().Where(x => x.Id == _operator.UserId).FirstOrDefaultAsync();
                foreach (var item in data.OutStorDetails)
                {
                    var materdata = await Db.GetIQueryable<IT_LocalMaterial>().Where(x => x.MaterialId == item.MaterialId && x.StorId == item.StorId && x.LocalId == item.LocalId).FirstOrDefaultAsync();
                    if (materdata == null)
                    {
                        //不存在新增
                        IT_LocalMaterial itdata = new IT_LocalMaterial();
                        itdata.Id = IdHelper.GetId();
                        itdata.MaterialId = item.MaterialId;
                        itdata.StorId = item.StorId;
                        itdata.LocalId = item.LocalId;
                        itdata.Nums_N = item.OutNum;
                        itdata.CreatorId = _operator.UserId;
                        itdata.CreateTime = DateTime.Now;
                        itdata.Deleted = false;
                        itdata.ScanNum = -item.OutNum;
                        itdata.CheckNum = 0;
                        await Db.InsertAsync<IT_LocalMaterial>(itdata);
                    }
                    else
                    {
                        //存在修改
                        string sqlMain = @"update IT_LocalMaterial set Nums_N=IFNULL(Nums_N,0)-" + item.OutNum + ",ScanNum=IFNULL(" +
                            "ScanNum,0)-" + item.OutNum + " where StorId='" + item.StorId + "' and LocalId='" + item.LocalId + "' and MaterialId='" + item.MaterialId + "';update PB_Material set CheckNum=IFNULL(CheckNum,0)-" + item.OutNum + ", ScanNum=IFNULL(ScanNum,0)-" + item.OutNum + " where Id='" + item.MaterialId + "'";
                        await ExecuteSqlAsync(sqlMain);
                    }
                    //库存明细表
                    IT_LocalDetail detdata = await Db.GetIQueryable<IT_LocalDetail>().Where(s => s.LocalId == item.LocalId && s.MaterialId == item.MaterialId).FirstOrDefaultAsync();
                    //detdata.Id = IdHelper.GetId();
                    detdata.StorId = item.StorId;
                    detdata.LocalId = item.LocalId;
                    detdata.MaterialId = item.MaterialId;
                    // detdata.MeasureId = Materialdata.storageId;
                    detdata.InTime = DateTime.Now;
                    detdata.CreateTime = DateTime.Now;
                    detdata.CreatorId = _operator.UserId;
                    detdata.Deleted = false;
                    detdata.Num = item.OutNum;
                    //detdata.BarCode = data.packqrcode;
                    // detdata.PackId = packId;
                    detdata.OldOrNew = 1;
                    await Db.UpdateAsync(detdata);

                    //插入库存明细表
                    PB_StockLog lodata = new PB_StockLog();
                    lodata.Id = IdHelper.GetId();
                    //  lodata.PackId = packId;
                    lodata.StorId = item.StorId;
                    lodata.LocationId = item.LocalId;
                    lodata.StockNumber = item.OutNum;
                    lodata.CreatorId = _operator.UserId;
                    lodata.CreatorName = bdata.RealName;
                    lodata.OperatorId = _operator.UserId;
                    lodata.OrderID = item.OutStorId;
                    lodata.CreateTime = DateTime.Now;
                    lodata.Type = 2;
                    lodata.State = 1;
                    lodata.OldOrNew = 1;
                    await Db.InsertAsync<PB_StockLog>(lodata);
                }
            }
            //为生产领料\备货\维修领料\外协\其它\无码\翻新出库审核通过新增库存台账记录。 牟俊明。2022.06.20
            //var bookSvc = _ServiceProvider.GetRequiredService<IIT_RecordBookBusiness>();
            //await bookSvc.AddByTypeAsync(audit.Id, "Out");
        }
        [DataEditLog(UserLogType.出库管理, "Id", "出库单审批")]
        [Transactional]
        public async Task OutReject(AuditDTO audit)
        {
            var data = await this.GetTheDataAsync(audit.Id);
            // 修改主数据状态
            {
                data.Status = 2;
                data.AuditeTime = audit.AuditTime;
                data.AuditUserId = audit.AuditUserId;
                await UpdateAsync(data);
            }
        }
        public async Task<AjaxResult> OutBlankTray(List<KeyValuePair<string, string>> listTray, string storid)
        {
           
                return Success("出空托盘成功!");

        }

        /// <summary>
        /// 自动分拣物料
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        [Transactional(System.Data.IsolationLevel.Serializable)]
        public async Task<AjaxResult<List<ReqMaterialResultDTO>>> ReqMaterial(ReqMaterialQM data)
        {
            var listResult = new List<ReqMaterialResultDTO>();
            // 是否按批次取物料
            if (data.BatchNo.IsNullOrEmpty())
            {
                //先检查物料是否满足数量
                var lmCountQuery = from lm in Db.GetIQueryable<IT_LocalMaterial>()
                                   join l in Db.GetIQueryable<PB_Location>() on lm.LocalId equals l.Id
                                   where lm.StorId == data.StorId
                                   && lm.MaterialId == data.MaterialId
                                   && l.StorId == data.StorId
                                   && l.LockType == 0
                                   group lm by lm.StorId into su
                                   select su.Sum(a => a.Nums_N);
                var lmCount = await lmCountQuery.FirstOrDefaultAsync();
                if (lmCount < data.Num) return new AjaxResult<List<ReqMaterialResultDTO>>() { Success = false, Msg = "库存不足" };

                var listLM = from lm in Db.GetIQueryable<IT_LocalMaterial>()
                             join l in Db.GetIQueryable<PB_Location>() on lm.LocalId equals l.Id
                             where lm.StorId == data.StorId
                             && l.IsForbid == false // 没有禁用
                             && lm.MaterialId == data.MaterialId
                             && l.StorId == data.StorId
                             && l.LockType == 0
                             orderby lm.Nums_N ascending, lm.Id ascending
                             select new ReqMaterialResultDTO()
                             {
                                 LocalId = lm.LocalId,
                                 MaterialId = lm.MaterialId,
                                 LocalNum = lm.Nums_N
                             };
                listResult = await listLM.ToListAsync();
            }
            else
            {
                //先检查物料是否满足数量
                var lmCountQuery = from lm in Db.GetIQueryable<IT_LocalMaterial>()
                                   join l in Db.GetIQueryable<PB_Location>() on lm.LocalId equals l.Id
                                   where lm.StorId == data.StorId
                                   && lm.MaterialId == data.MaterialId
                                   && l.StorId == data.StorId
                                   && l.LockType == 0
                                   group lm by lm.StorId into su
                                   select su.Sum(a => a.Nums_N);
                var lmCount = await lmCountQuery.FirstOrDefaultAsync();
                if (lmCount < data.Num) return new AjaxResult<List<ReqMaterialResultDTO>>() { Success = false, Msg = "库存不足" };

                var listLM = from lm in Db.GetIQueryable<IT_LocalMaterial>()
                             join l in Db.GetIQueryable<PB_Location>() on lm.LocalId equals l.Id
                             where lm.StorId == data.StorId
                             && l.IsForbid == false // 没有禁用
                             && lm.MaterialId == data.MaterialId
                             && l.StorId == data.StorId
                             && l.LockType == 0
                             orderby lm.Nums_N ascending, lm.Id ascending
                             select new ReqMaterialResultDTO()
                             {
                                 LocalId = lm.LocalId,
                                 MaterialId = lm.MaterialId,
                                 LocalNum = lm.Nums_N
                             };
                listResult = await listLM.ToListAsync();
            }

            var result = new List<ReqMaterialResultDTO>();
            double diffNum = data.Num;
            foreach (var item in listResult)
            {
                if (diffNum <= 0) break;
                if (item.LocalNum <= diffNum)
                    item.OutNum = item.LocalNum;
                else
                    item.OutNum = diffNum;
                result.Add(item);
                diffNum -= item.OutNum;
            }
            if (diffNum > 0) return new AjaxResult<List<ReqMaterialResultDTO>>() { Success = false, Msg = "可用库存不足" };

            // 锁定货位
            {
                var localIds = result.Select(s => s.LocalId).ToList();
                var listLocal = await Db.GetIQueryable<PB_Location>().Where(w => localIds.Contains(w.Id)).ToListAsync();
                foreach (var item in listLocal)
                {
                    item.LockType = 2;
                }
                var localSvc = _ServiceProvider.GetRequiredService<IPB_LocationBusiness>();
                await localSvc.UpdateDataAsync(listLocal);
            }

            return new AjaxResult<List<ReqMaterialResultDTO>>() { Success = true, Data = result, Msg = "分拣成功" };
        }

        public  async Task<PageResult<TD_OutStorage>> GetDataListAsyncGroup(TD_OutStoragePageInput input)
        {
            var q = GetIQueryable();
            var where = LinqHelper.True<TD_OutStorage>();
            var search = input.Search;


            if (search.Status.HasValue)
                where = where.And(w => w.Status == search.Status.Value);
            if (!search.Code.IsNullOrEmpty())
                where = where.And(w => w.Code.Contains(search.Code) || w.RefCode.Contains(search.Code));
            if (!search.OutType.IsNullOrEmpty())
                where = where.And(w => w.OutType == search.OutType);
            if (search.OutStorTimeStart.HasValue)
                where = where.And(w => w.OutTime >= search.OutStorTimeStart.Value);
            if (search.OutStorTimeEnd.HasValue)
                where = where.And(w => w.OutTime <= search.OutStorTimeEnd.Value);
            q = q.Where(m=>m.OutType== "SaleOut");
            return await q.Where(where).GetPageResultAsync(input);
        }

   public  async   Task<PageResult<ProjectSummaryDTO>> GetProjectSummary(PageInput<ProjectSummaryContionDTO> input) {
            string sql = @"SELECT
	e.`Id` AS `BuildingnumberId`,
	e.`Buildingnumber`,
	m.`Name` AS 	`MaterialName`,	
 m.`Spec` as `MaterialSpec`	,
	m.`ProductCode`,
  
	m.`Code`,
	a.`OutTime`,
	a.`ProjectId`,
	c.`Name` as `ProjectName`,
	t.`Name` AS `DeptName`,
p.`Id` AS `Pid`,
R.`Name` as `CustomerName`	,
	SUM(
	IFNULL( b.OutNum, 0 )) OutNums ,
SUM(
	IFNULL( m.Weight, 0 )) Weight 
FROM
	TD_OutStorage a
	INNER JOIN TD_OutStorDetail b ON a.Id = b.OutStorId
	INNER JOIN PB_Project c ON a.ProjectId = c.Id
	INNER JOIN Base_Department t ON c.DeptId = t.Id
	INNER JOIN PB_DesignList d ON a.DesignId = d.Id
	INNER JOIN PB_Buildingnumber e ON d.BuildingNumberID = e.Id 
	INNER JOIN PB_Material  m ON b.MaterialId=m.Id
	INNER JOIN PB_DeliveryNotice p ON p.ProjectId=c.Id
  INNER JOIN PB_Customer R ON  p .SaleUnitId=R.Id
	where 	a.Id is not null and  b.OutNum>0 {0}{1}
GROUP BY
	e.`Id`,b.`MaterialId`, a.`Id`,c.`Id`,t.`Id` , p.`Id`    
	";
            string ProjectName = "";
            string time = "";
            string CustomerName = "";
            if (!string.IsNullOrEmpty(input.Search.ProjectName))
            {
                ProjectName += " AND c.Name  like '%" + input.Search.ProjectName + "%' ";
            }
            if (!string.IsNullOrEmpty(input.Search.OrderTimeStart.ToString())&&!string.IsNullOrEmpty(input.Search.OrderTimeEnd.ToString())) {
                time += "and a.OutTime   between    '"+input.Search.OrderTimeStart+"' and '"+input.Search.OrderTimeEnd+" '";
            }
            if (!string.IsNullOrEmpty(input.Search.CustomerName))
            {
                ProjectName += " AND R.Name  like '%" + input.Search.CustomerName + "%' ";
            }
            sql = string.Format(sql, ProjectName, time);
            var res = await Db.GetListBySqlAsync<ProjectSummaryDTO>(sql);
            #region   分页处理数据   有bug 没有按照主数据进行处理
            int pagecount;//总页数
            List<ProjectSummaryDTO> listpro_down = res.ToList();//一个要分页的，类型数据集合，存储的是所有的数据
            List<ProjectSummaryDTO> productes = new List<ProjectSummaryDTO>();//用来存储要展示的数据
            int pagees = listpro_down.Count;//所有数据的总条数
                                            //计算总页数
            if (pagees % input.PageRows == 0)
            {
                pagecount = pagees / input.PageRows;
            }
            else
            {
                pagecount = (pagees / input.PageRows) + 1;
            }
            productes = listpro_down.Skip((input.PageIndex - 1) * input.PageRows).Take(input.PageRows).ToList();//分页的重点
            return new PageResult<ProjectSummaryDTO> { Data = productes, Total = pagees };
            #endregion
        }
        public  async Task<TD_OutStorageInfo> GetTD_OutStorageinfo(string ParentId)
        {
            Expression<Func< TD_OutStorage, Base_Department ,TD_OutStorageInfo >> select = (a, b) => new TD_OutStorageInfo
            {
StorageIdName=b.Name,
            };
            select = select.BuildExtendSelectExpre();
            var q = from a in GetIQueryable().AsExpandable()
                    join b in Db.GetIQueryable<Base_Department>() on a.StorageId equals b.Id into ab
                    from b in ab.DefaultIfEmpty()                            
                    select @select.Invoke(a, b);
            TD_OutStorageInfo listdata = new TD_OutStorageInfo();
            var qdata = await q.Where(x => x.Id == ParentId).FirstOrDefaultAsync();

            Expression<Func<TD_OutStorDetail, Base_Department,PB_Location,PB_StorArea,PB_Rack,PB_Material,TD_OutStorDetailDTO>> selects = (a,b,c,d,e,f) => new TD_OutStorDetailDTO
            {
                StorIdName=b.Name,
                LocalIdName=c.Name,
                AreaIdName=d.Name,
                RackIdName=e.Name,
                MaterialIdName=f.Name,
                Spec=f.Spec,
            };
            selects = selects.BuildExtendSelectExpre();
            var k = from a in Db.GetIQueryable<TD_OutStorDetail>().AsExpandable()
                    join b in Db.GetIQueryable<Base_Department>() on a.StorId equals b.Id into ab
                    from b in ab.DefaultIfEmpty()
                    join c in Db.GetIQueryable<PB_Location>() on a.LocalId equals c.Id into ac
                    from c in ac.DefaultIfEmpty()
                    join d in Db.GetIQueryable<PB_StorArea>() on a.AreaId equals d.Id into ad
                    from d in ad.DefaultIfEmpty()
                    join e in Db.GetIQueryable<PB_Rack>() on a.RackId equals e.Id into ae
                    from e in ae.DefaultIfEmpty()
                    join f in Db.GetIQueryable<PB_Material>() on a.MaterialId equals f.Id into af
                    from f in af.DefaultIfEmpty()
                    select @selects.Invoke(a,b,c,d,e,f);
            k = k.Where(x => x.OutStorId == qdata.Id);
            var res = await k.ToListAsync();
            TD_OutStorageInfo pblist = new TD_OutStorageInfo();
            pblist.QrCode = qdata.QrCode;
            pblist.StorageIdName = qdata.StorageIdName;
            pblist.OutTime = qdata.OutTime;
            pblist.OutNum = qdata.OutNum;
            pblist.Subdata = res;
            if (res != null)
            {
                return pblist;
            }
            else
            {
                throw new BusException("暂无数据");
            }
        }

        public  async Task<PageResult<TD_OutStorage>> GetDataListAsyncScrap(TD_OutStoragePageInput input)
        {
            var q = GetIQueryable();
            var where = LinqHelper.True<TD_OutStorage>();
            var search = input.Search;


            if (search.Status.HasValue)
                where = where.And(w => w.Status == search.Status.Value);
            if (!search.Code.IsNullOrEmpty())
                where = where.And(w => w.Code.Contains(search.Code) || w.RefCode.Contains(search.Code));
            if (!search.OutType.IsNullOrEmpty())
                where = where.And(w => w.OutType == search.OutType);
            if (search.OutStorTimeStart.HasValue)
                where = where.And(w => w.OutTime >= search.OutStorTimeStart.Value);
            if (search.OutStorTimeEnd.HasValue)
                where = where.And(w => w.OutTime <= search.OutStorTimeEnd.Value);
            q = q.Where(m => m.OutType == "ScrapOut");
            return await q.Where(where).GetPageResultAsync(input);
        }

        public  async Task<PageResultData<OutStoreDetail>> OutStoreDetail(PageInput<ProjectSummaryContionDTO> input)
        {
            string sql = @"	
	SELECT
	sto.`Name` Warehouse,
	m.`Code` materialCode,
	m.`Name` MaterName,
	sum( a.OutNum ) OutNums,
	m.Id MaterialId,
	m.Spec materialSpce,
	IFNULL( m.Weight, 0 ) Weight,
	IFNULL( SUM( a.OutNum )* m.Weight, 0 )  materialWeight
FROM
	TD_OutStorDetail AS a
	LEFT JOIN Base_Department AS sto ON a.StorId = sto.Id
	LEFT JOIN PB_Material AS m ON a.MaterialId = m.Id 
where 1=1 {0} {1} {2}
GROUP BY
	a.MaterialId,
	a.StorId 
	";
            string time = "";
            string Strarea = "";
            string MatelName = "";
            if (!string.IsNullOrEmpty(input.Search.OrderTimeStart.ToString()) && !string.IsNullOrEmpty(input.Search.OrderTimeEnd.ToString()))
            {
                time += "  and a.CreateTime between   '" + Convert.ToDateTime(input.Search.OrderTimeStart).ToString("yyyy-MM-dd 00:00:00") + "'   and '"+ Convert.ToDateTime(input.Search.OrderTimeEnd).ToString("yyyy-MM-dd 23:59:59") +"'";
            }
            if (!string.IsNullOrEmpty(input.Search.StrareaName))
            {
                Strarea += "and sto.Id = '" + input.Search.StrareaName + "'";
            }
            if (!string.IsNullOrEmpty(input.Search.MaterialNameOrCode))
            {
                MatelName += "  and (m.`Name` like '%"+input.Search.MaterialNameOrCode+ "%' or  m.`Code" +
                    "` like '%" + input.Search.MaterialNameOrCode + "%')";
            }
          
            sql = string.Format(sql, MatelName, Strarea,time );



            var res = await Db.GetListBySqlAsync<OutStoreDetail>(sql);
            #region   分页处理数据   有bug 没有按照主数据进行处理
            int pagecount;//总页数
            List<OutStoreDetail> listpro_down = res.ToList();//一个要分页的，类型数据集合，存储的是所有的数据
            List<OutStoreDetail> productes = new List<OutStoreDetail>();//用来存储要展示的数据
            int pagees = listpro_down.Count;//所有数据的总条数
                                            //计算总页数
            if (pagees % input.PageRows == 0)
            {
                pagecount = pagees / input.PageRows;
            }
            else
            {
                pagecount = (pagees / input.PageRows) + 1;
            }
            double? TotalQuantity = 0;
            double? TotalWeight = 0;
            for (int i = 0; i < res.Count; i++)
            {
                TotalQuantity += res[i].OutNums;
                TotalWeight += res[i].materialWeight;
            }
            productes = listpro_down.Skip((input.PageIndex - 1) * input.PageRows).Take(input.PageRows).ToList();//分页的重点
            return new PageResultData<OutStoreDetail> { Data = productes, Total = pagees,TotalQuantity=TotalQuantity.ToString(),TotalWeight=TotalWeight.ToString() };
            #endregion
        }

        /// <summary>
        /// 大屏显示当月生产领料吨数
        /// </summary>
        /// <param name="Month">前第几月</param>
        /// <returns></returns>
        public ScreenDisplayValueDTO GetMonthProductOut(int Month)
        {
            //原材料的时候，重量是1
            string strSQL = @"SELECT IFNULL(SUM(t.OutNum*t.Weight)/1000,0) as value
FROM
(SELECT od.OutNum,IF(m.IsProduct=0 AND Weight=0,1,m.Weight) AS Weight
FROM TD_OutStorDetail od
JOIN PB_Material m ON od.MaterialId=m.Id
JOIN TD_OutStorage os ON os.OutType='ProductOut' AND od.OutStorId=os.Id AND date_format(os.OutTime, '%Y %m')=date_format(DATE_SUB(curdate(), INTERVAL "+Month.ToString()+@" MONTH),'%Y %m')) t";
            ScreenDisplayValueDTO res = Db.GetListBySqlAsync<ScreenDisplayValueDTO>(strSQL).Result.FirstOrDefault();
            res.value = Convert.ToDouble(res.value.ToString("#0.##"));
            return res;          
        }
    }
    
}